home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / DEMON / RISCOS2 / TCP_131S.ARC / c / NR4 < prev    next >
Text File  |  1993-12-22  |  27KB  |  707 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <time.h>
  8. #include <ctype.h>
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "timer.h"
  12. #include "ax25.h"
  13. #include "lapb.h"
  14. #include "netrom.h"
  15. #include "nr4.h"
  16. #include "misc.h"
  17.  
  18. #undef NR4DEBUG
  19.  
  20. /* Globals: */
  21.  
  22. /* The circuit table */
  23.  
  24. struct nr4circp Nr4circuits[NR4MAXCIRC] ;
  25.  
  26. /* Various limits */
  27.  
  28. unsigned Nr4window = 4 ;                /* Max window to negotiate */
  29. unsigned Nr4retries = 10 ;              /* Max retries */
  30. unsigned Nr4qlimit = 2048 ;             /* Max bytes on receive queue */
  31.  
  32. /* Timers */
  33.  
  34. long Nr4irtt = 15000 ;                  /* Initial round trip time */
  35. long Nr4acktime = 3000 ;                /* ACK delay timer */
  36. long Nr4choketime = 180000 ;    /* CHOKEd state timeout */
  37.  
  38.  
  39. /* This function is called when a net/rom layer four frame */
  40. /* is discovered inside a datagram addressed to us */
  41.  
  42. void nr4input(struct nr4hdr *hdr, struct mbuf *bp)
  43. {
  44.         struct nr4hdr rhdr ;
  45.         struct nr4cb *cb ;
  46.         struct ax25_addr dest ;
  47.         int op ;
  48.         unsigned window ;
  49.         int acceptc ;           /* indicates that connection should be accepted */
  50.         int newconn ;           /* indicates that this is a new incoming */
  51.                                                 /* connection.  You'll see. */
  52.         int gotchoke ;          /* The choke flag was set in this packet */             
  53.         
  54.         op = hdr->opcode & NR4OPCODE ;  /* Mask off flags */
  55.         
  56.         if (op == NR4OPCONRQ) {                 /* process connect request first */
  57.                 acceptc = 1 ;
  58.                 newconn = 0 ;
  59.  
  60.                 /* These fields are sent regardless of success */
  61.                 
  62.                 rhdr.yourindex = hdr->u.conreq.myindex ;
  63.                 rhdr.yourid = hdr->u.conreq.myid ;
  64.                 dest = hdr->u.conreq.node ;
  65.  
  66.                 /* Check to see if we have already received a connect */
  67.                 /* request for this circuit. */
  68.  
  69.                 if ((cb = match_n4circ(hdr->u.conreq.myindex, hdr->u.conreq.myid,
  70.                                                                   &hdr->u.conreq.user, &hdr->u.conreq.node))
  71.                          == NULLNR4CB) {        /* No existing circuit if NULL */
  72.  
  73.                         /* Try to get a new circuit */
  74.  
  75.                         if ((cb = new_n4circ()) == NULLNR4CB) {
  76.                                 acceptc = 0 ;
  77.                         } else {
  78.                         
  79.                                 /* Window is set to min of the offered and local windows */
  80.                                 
  81.                                 window = hdr->u.conreq.window > Nr4window ?
  82.                                                  Nr4window : hdr->u.conreq.window ;
  83.  
  84.                                 if (init_nr4window(cb, window) == -1) {
  85.                                         free_n4circ(cb) ;
  86.                                         acceptc = 0 ;
  87.                                 } else {
  88.                                         /* Set up control block */
  89.                                         cb->yournum = hdr->u.conreq.myindex ;
  90.                                         cb->yourid = hdr->u.conreq.myid ;
  91.                                         cb->user = hdr->u.conreq.user ;
  92.                                         cb->node = hdr->u.conreq.node ;
  93.                                         cb->luser = mycall ;/* we are local user on incomings */
  94.                                         cb->srtt = Nr4irtt ;/* Default round trip time */
  95.                                         nr4defaults(cb) ;       /* set up timers, window pointers */
  96.                                         cb->s_upcall = nr4_incom ;
  97.                                         cb->state = NR4STDISC ;
  98.                                         newconn = 1 ;
  99.                                 } /* End if window successfully allocated */
  100.                                 
  101.                         }       /* End if new circuit available */
  102.                         
  103.                  } /* End if no existing circuit matching parameters */
  104.                  
  105.                 /* Now set up response */
  106.  
  107.                 if (!acceptc) {
  108.                         rhdr.opcode = NR4OPCONAK | NR4CHOKE ;/* choke means reject */
  109.                         rhdr.u.conack.myindex = 0 ;
  110.                         rhdr.u.conack.myid = 0 ;
  111.                         rhdr.u.conack.window = 0 ;
  112.                 } else {
  113.                         rhdr.opcode = NR4OPCONAK ;
  114.                         rhdr.u.conack.myindex = cb->mynum ;
  115.                         rhdr.u.conack.myid = cb->myid ;
  116.                         rhdr.u.conack.window = cb->window ;
  117.                 }
  118.                 nr4sframe(&dest, &rhdr, NULLBUF) ;
  119.  
  120.                 /* Why, you ask, do we wait until now for the state change */
  121.                 /* upcall?  Well, it's like this:  if the state change triggers */
  122.                 /* something like the mailbox to send its banner, the banner */
  123.                 /* would have gone out *before* the conn ack if we'd done this */
  124.                 /* in the code above.  This is what happens when you don't plan */
  125.                 /* too well.  Learn from my mistakes :-) */
  126.                 
  127.                 if (newconn)
  128.                         nr4state(cb, NR4STCON) ;/* connected (no 3-way handshake) */
  129.                         
  130.                 free_p(bp) ;
  131.                 return ;
  132.         } /* end connect request code */
  133.  
  134.         /* validate circuit number */
  135.  
  136.         if ((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULLNR4CB) {
  137.                 free_p(bp) ;
  138.                 return ;
  139.         }
  140.  
  141.         /* Check for choke flag */
  142.  
  143.         if (hdr->opcode & NR4CHOKE)
  144.                 gotchoke = 1 ;
  145.         else
  146.                 gotchoke = 0 ;
  147.         
  148.         /* Here's where the interesting stuff gets done */
  149.  
  150.         switch (cb->state) {
  151.           case NR4STCPEND:
  152.             switch (op) {
  153.                   case NR4OPCONAK:
  154.                         stop_timer(&cb->tcd) ;
  155.                     if (gotchoke) {                                     /* connect rejected */
  156.                                 cb->dreason = NR4RREFUSED ;
  157.                                 nr4state(cb, NR4STDISC) ;
  158.                                 break ;
  159.                         }
  160.                         cb->yournum = hdr->u.conack.myindex ;
  161.                         cb->yourid = hdr->u.conack.myid ;
  162.                         window = hdr->u.conack.window > Nr4window ?
  163.                                          Nr4window : hdr->u.conack.window ;
  164.  
  165.                         if (init_nr4window(cb, window) == -1) {
  166.                                 cb->dreason = NR4RRESET ;
  167.                                 nr4state(cb, NR4STDISC) ;
  168.                         } else {
  169.                                 nr4defaults(cb) ;       /* set up timers, window pointers */
  170.                                 
  171.                                 if (cb->cdtries == 1)                   /* No retries */
  172.                                         cb->srtt = cb->tcd.count * MSPTICK ;/* Use measured rtt */
  173.                                 else
  174.                                         cb->srtt = Nr4irtt ;            /* else use default */
  175.                                         
  176.                                 nr4state(cb, NR4STCON) ;
  177.                                 nr4output(cb) ;         /* start sending anything on the txq */
  178.                         }
  179.                         break ;
  180.  
  181.                   default:              /* We can't respond to anything else without */
  182.                                                 /* Their ID and index */
  183.                         free_p(bp) ;
  184.                         return ;
  185.                 }
  186.                 break ;
  187.                 
  188.           case NR4STCON:
  189.             switch (op) {
  190.                   case NR4OPDISRQ:
  191.                         /* format reply packet */
  192.                         rhdr.opcode = NR4OPDISAK ;
  193.                         rhdr.yourindex = cb->yournum ;
  194.                         rhdr.yourid = cb->yourid ;
  195.         
  196.                         nr4sframe(&cb->node, &rhdr, NULLBUF) ;
  197.  
  198.                         cb->dreason = NR4RREMOTE ;
  199.                         nr4state(cb, NR4STDISC) ;
  200.  
  201.                         break ;
  202.                         
  203.                   case NR4OPINFO:
  204.                         /* Do receive frame processing */
  205.                         nr4rframe(cb, hdr->u.info.txseq, bp) ;
  206.  
  207.                         /* Reset the choke flag if no longer choked.  Processing */
  208.                         /* the ACK will kick things off again. */
  209.                         
  210.                         if (cb->choked && !gotchoke) {
  211.                                 stop_timer(&cb->tchoke) ;
  212.                                 cb->choked = 0 ;
  213.                         }
  214.                                 
  215.                         /* We delay processing the receive sequence number until */
  216.                         /* now, because the ACK might pull more off the txq and send */
  217.                         /* it, and we want the implied ACK in those frames to be right */
  218.  
  219.                         /* Only process NAKs if the choke flag is off.  It appears */
  220.                         /* that NAKs should never be sent with choke on, by the way, */
  221.                         /* but you never know, considering that there is no official */
  222.                         /* standard for this protocol */
  223.                         
  224.                         if (hdr->opcode & NR4NAK && !gotchoke)
  225.                                 nr4gotnak(cb, hdr->u.info.rxseq) ;
  226.  
  227.                         /* We always do ACK processing, too, since the NAK of one */
  228.                         /* packet may be the implied ACK of another.  The gotchoke */
  229.                         /* flag is used to prevent sending any new frames, since */
  230.                         /* we are just going to purge them next anyway if this is */
  231.                         /* the first time we've seen the choke flag.  If we are */
  232.                         /* already choked, this call will return immediately. */
  233.                         
  234.                         nr4ackours(cb, hdr->u.info.rxseq, gotchoke) ;
  235.  
  236.                         /* If we haven't seen the choke flag before, purge the */
  237.                         /* send window and set the timer and the flag. */
  238.                         
  239.                         if (!cb->choked && gotchoke)
  240.                                 nr4choke(cb) ;
  241.                         
  242.                         break ;
  243.  
  244.                   case NR4OPACK:
  245.                         if (cb->choked && !gotchoke) {  /* clear choke if appropriate */
  246.                                 stop_timer(&cb->tchoke) ;
  247.                                 cb->choked = 0 ;
  248.                         }
  249.                                 
  250.                         if (hdr->opcode & NR4NAK && !gotchoke)
  251.                                 nr4gotnak(cb, hdr->u.ack.rxseq) ;       /* process NAKs */
  252.                                 
  253.                         nr4ackours(cb, hdr->u.ack.rxseq, gotchoke) ; /* and ACKs */
  254.  
  255.                         if (!cb->choked && gotchoke)    /* First choke seen */
  256.                                 nr4choke(cb) ;                          /* Set choke status */
  257.  
  258.                         break ;
  259.                 }
  260.                 break ;
  261.                 
  262.           case NR4STDPEND:
  263.             switch (op) {
  264.                   case NR4OPDISAK:
  265.                         cb->dreason = NR4RNORMAL ;
  266.                         nr4state(cb, NR4STDISC) ;
  267.                         break ;
  268.                         
  269.                   case NR4OPINFO:
  270.                         /* We can still do receive frame processing until */
  271.                         /* the disconnect acknowledge arrives, but we won't */
  272.                         /* bother to process ACKs, since we've flushed our */
  273.                         /* transmit buffers and queue already. */
  274.                         
  275.                         nr4rframe(cb, hdr->u.info.txseq, bp) ;
  276.  
  277.                         break ;
  278.                 }
  279.         
  280.         }       /* End switch(state) */
  281.  
  282. }
  283.  
  284.  
  285. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  286.  * type is info.
  287.  */
  288.  
  289. void nr4sframe(struct ax25_addr *dest, struct nr4hdr *hdr, struct mbuf *bp)
  290. {
  291.         struct mbuf *n4b ;
  292.  
  293.         if ((n4b = htonnr4(hdr)) == NULLBUF) {
  294.                 free_p(bp) ;
  295.                 return ;
  296.         } else {
  297.                 append(&n4b, bp) ;
  298.                 nr3output(dest, n4b) ;
  299.         }
  300. }
  301.  
  302. /* Receive frame processing */
  303.  
  304. void nr4rframe(struct nr4cb *cb, unsigned rxseq, struct mbuf *bp)
  305. {
  306.         struct nr4hdr rhdr ;
  307.         unsigned window = cb->window ;
  308.         unsigned rxbuf = rxseq % window ;
  309.         unsigned newdata = 0 ;          /* whether to upcall */
  310.  
  311. #ifdef NR4DEBUG
  312.         cwprintf(NULL, "Processing received info\r\n") ;
  313. #endif
  314.  
  315.         /* If we're choked, just reset the ACK timer to blast out */
  316.         /* another CHOKE indication after the ackdelay */
  317.  
  318.         if (cb->qfull) {
  319.                 start_timer(&cb->tack) ;
  320.                 return ;
  321.         }
  322.         
  323.         /* If the frame is out of sequence, NAK it if we haven't */
  324.         /* already done so */
  325.         
  326.         if (rxseq != cb->rxpected && !cb->naksent) {
  327. #ifdef NR4DEBUG
  328.                 cwprintf(NULL, "Frame out of sequence -- expected %u, got %u.\r\n",
  329.                            cb->rxpected, rxseq) ;
  330. #endif                          
  331.                 rhdr.opcode = NR4OPACK | NR4NAK ;
  332.                 rhdr.yourindex = cb->yournum ;
  333.                 rhdr.yourid = cb->yourid ;
  334.                 rhdr.u.ack.rxseq = cb->rxpected ;
  335.                 nr4sframe(&cb->node, &rhdr, NULLBUF) ;
  336.                 
  337.                 /* Now make sure we don't send any more of these until */
  338.                 /* we see some good data.  Otherwise full window retransmissions */
  339.                 /* would result in a flurry of NAKs */
  340.                 
  341.                 cb->naksent = 1 ;
  342.         }
  343.                         
  344.         /* If this is a new frame, within the window, buffer it, */
  345.         /* then see what we can deliver */
  346.                         
  347.         if (nr4between(cb->rxpected,rxseq,cb->rxpastwin)
  348.                 && !cb->rxbufs[rxbuf].occupied) {
  349. #ifdef NR4DEBUG
  350.                 cwprintf(NULL, "Frame within window\r\n") ;
  351. #endif
  352.                 cb->rxbufs[rxbuf].occupied = 1 ;
  353.                 cb->rxbufs[rxbuf].data = bp ;
  354.                                 
  355.                 for (rxbuf = cb->rxpected % window ; cb->rxbufs[rxbuf].occupied ; 
  356.                          rxbuf = cb->rxpected % window) {
  357. #ifdef NR4DEBUG
  358.                         cwprintf(NULL, "Removing frame from buffer %d\r\n", rxbuf) ;
  359. #endif
  360.                         newdata = 1 ;
  361.                         cb->rxbufs[rxbuf].occupied = 0 ;
  362.                         append(&cb->rxq,cb->rxbufs[rxbuf].data) ;
  363.                         cb->rxbufs[rxbuf].data = NULLBUF ;
  364.                         cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK ;
  365.                         cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK ;
  366.                 }
  367.                 if (newdata) {
  368.                         cb->naksent = 0 ;       /* OK to send NAKs again */
  369.                         if (cb->r_upcall != NULLVFP)
  370.                                 (*cb->r_upcall)(cb,len_mbuf(cb->rxq)) ;
  371.  
  372.                         /* Now that our upcall has had a shot at the queue, */
  373.                         /* see if it's past the queue length limit.  If so, */
  374.                         /* go into choked mode (i.e. flow controlled). */
  375.  
  376.                         if (len_mbuf(cb->rxq) > Nr4qlimit) {
  377.                                 cb->qfull = 1 ;
  378.                                 nr4ackit((char *)cb) ;  /* Tell `em right away */
  379.                         } else
  380.                                 start_timer(&cb->tack) ;
  381.                 }
  382.         } else  /* It's out of the window or we've seen it already */
  383.                 free_p(bp) ;
  384. }
  385.  
  386.  
  387. /* Send the transmit buffer whose sequence number is seq */
  388.  
  389. void nr4sbuf(struct nr4cb *cb, unsigned seq)
  390. {
  391.         struct nr4hdr hdr ;
  392.         struct mbuf *bufbp, *bp ;
  393.         unsigned bufnum = seq % cb->window ;
  394.         struct timer *t ;
  395.         
  396.         /* sanity check */
  397.  
  398.         if (bufnum >= cb->window) {
  399. #ifdef NRDEBUG
  400.                 cwprintf(NULL, "sbuf: buffer number %u beyond window\r\n",bufnum) ;
  401. #endif
  402.                 return ;
  403.         }
  404.  
  405.         /* Stop the ACK timer, since our sending of the frame is */
  406.         /* an implied ACK. */
  407.  
  408.         stop_timer(&cb->tack) ;
  409.         
  410.         /* Duplicate the mbuf, since we have to keep it around */
  411.         /* until it is acknowledged */
  412.         
  413.         bufbp = cb->txbufs[bufnum].data ;
  414.  
  415.         /* Notice that we use copy_p instead of dup_p.  This is because */
  416.         /* a frame can still be sitting on the AX.25 send queue when it */
  417.         /* get acknowledged, and we don't want to deallocate its data */
  418.         /* before it gets sent! */
  419.         
  420.         if ((bp = copy_p(bufbp, len_mbuf(bufbp))) == NULLBUF) {
  421.                 free_mbuf(bp) ;
  422.                 return ;
  423.         }
  424.  
  425.         /* Prepare the header */
  426.         if (cb->qfull)                          /* are we choked? */
  427.                 hdr.opcode = NR4OPINFO | NR4CHOKE ;
  428.         else
  429.                 hdr.opcode = NR4OPINFO ;
  430.         hdr.yourindex = cb->yournum ;
  431.         hdr.yourid = cb->yourid ;
  432.         hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK) ;
  433.         hdr.u.info.rxseq = cb->rxpected ;
  434.         
  435.         /* Send the frame, then set and start the timer */
  436.  
  437.         nr4sframe(&cb->node, &hdr, bp) ;
  438.  
  439.         t = &cb->txbufs[bufnum].tretry ;
  440.         t->start = ((int32)1 << cb->blevel) *
  441.                            (2 * cb->mdev + cb->srtt + MSPTICK) / MSPTICK ;
  442.         start_timer(t) ;
  443.  
  444.         return ;
  445. }
  446.  
  447. /* Check to see if any of our frames have been ACKed */
  448.  
  449. void nr4ackours(struct nr4cb *cb, unsigned seq, int gotchoke)
  450. {
  451.         unsigned txbuf ;
  452.         struct timer *t ;
  453.         
  454.         /* If we are choked, there is nothing in the send window */
  455.         /* by definition, so we can just return. */
  456.         
  457.         if (cb->choked)
  458.                 return ;
  459.                 
  460.         /* Adjust seq to point to the frame being ACK'd, not the one */
  461.         /* beyond it, which is how it arrives. */
  462.  
  463.         seq = (seq - 1) & NR4SEQMASK ;
  464.  
  465.         /* Free up all the ack'd frames, and adjust the round trip */
  466.         /* timing stuff */
  467.         
  468.         while (nr4between(cb->ackxpected, seq, cb->nextosend)) {
  469. #ifdef NR4DEBUG
  470.                 cwprintf(NULL, "Sequence # %u acknowledged\r\n", seq) ;
  471. #endif
  472.                 cb->nbuffered-- ;
  473.                 txbuf = cb->ackxpected % cb->window ;
  474.                 stop_timer(&cb->txbufs[txbuf].tretry) ;
  475.                 free_mbuf(cb->txbufs[txbuf].data) ;
  476.                 cb->txbufs[txbuf].data = NULLBUF ;
  477.                 cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK ;
  478.  
  479.                 /* Round trip time estimation, cribbed from TCP */
  480.  
  481.                 if (cb->txbufs[txbuf].retries == 0) {   /* We only sent this one once */
  482.                         int32 rtt ;
  483.                         int32 abserr ;
  484.  
  485.                         t = &cb->txbufs[txbuf].tretry ;
  486.                         rtt = (t->start - t->count) * MSPTICK ; /* get our rtt in msec */
  487.                         abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt ;
  488.                         cb->srtt = (cb->srtt * 7 + rtt) >> 3 ;
  489.                         cb->mdev = (cb->mdev * 3 + abserr) >> 2 ;
  490.  
  491.                         /* Reset the backoff level */
  492.  
  493.                         cb->blevel = 0 ;
  494.                 } 
  495.         }
  496.  
  497.         /* Now we recalculate tmax, the maximum number of retries for */
  498.         /* any frame in the window.  tmax is used as a baseline to */
  499.         /* determine when the window has reached a new high in retries. */
  500.         /* We don't want to increment blevel for every frame that times */
  501.         /* out, since that would lead to us backing off too fast when */
  502.         /* all the frame timers expired at around the same time. */
  503.  
  504.         cb->txmax = 0 ;
  505.         
  506.         for (seq = cb->ackxpected ;
  507.                  nr4between(cb->ackxpected, seq, cb->nextosend) ;
  508.                  seq = (seq + 1) & NR4SEQMASK)
  509.                 if (cb->txbufs[seq % cb->window].retries > cb->txmax)
  510.                         cb->txmax = cb->txbufs[seq % cb->window].retries ;
  511.  
  512.         /* This is kind of a hack.  This function is called under */
  513.         /* three different conditions:  either we are choked, in */
  514.         /* which case we return immediately, or we are not choked, */
  515.         /* in which case we proceed normally to keep the send */
  516.         /* window full, or we have seen the choke flag for the first */
  517.         /* time.  In the last case, gotchoke is true while cb->choked */
  518.         /* is false.  We want to process any acknowledgments of existing */
  519.         /* frames in the send window before we purge it, while at the */
  520.         /* same time we don't want to take anything else off the txq */
  521.         /* or send it out.  So, in the third case we listed, we return */
  522.         /* now since we've processed the ACK. */
  523.         
  524.         if (gotchoke)
  525.                 return ;
  526.                 
  527.         nr4output(cb) ;                 /* yank stuff off txq and send it */
  528.  
  529.         /* At this point, either the send window is full, or */
  530.         /* nr4output() didn't find enough on the txq to fill it. */
  531.         /* If the window is not full, then the txq must be empty, */
  532.         /* and we'll make a tx upcall */
  533.         
  534.         if (cb->nbuffered < cb->window) 
  535.                 if (cb->t_upcall != NULLVFP)
  536.                         (*cb->t_upcall)(cb, (cb->window - cb->nbuffered) * NR4MAXINFO) ;
  537.  
  538. }
  539.  
  540.  
  541. /* If the send window is open and there are frames on the txq,
  542.  * move as many as possible to the transmit buffers and send them.
  543.  * Return the number of frames sent.
  544.  */
  545.  
  546. int nr4output(struct nr4cb *cb)
  547. {
  548.         int numq, i ;
  549.         struct mbuf *bp ;
  550.         struct nr4txbuf *tp ;
  551.  
  552.         /* Are we in the proper state? */
  553.  
  554.         if (cb->state != NR4STCON || cb->choked)
  555.                 return 0 ;                              /* No sending if not connected */
  556.                                                                 /* or if choked */
  557.                 
  558.         /* See if the window is open */
  559.         
  560.         if (cb->nbuffered >= cb->window)
  561.                 return 0 ;
  562.  
  563.         numq = len_q(cb->txq) ;
  564.         
  565. #ifdef NR4DEBUG
  566.         cwprintf(NULL, "nr4output: %d packets on txq\r\n", numq) ;
  567. #endif
  568.         
  569.         for (i = 0 ; i < numq ; i++) {
  570.  
  571.                 bp = dequeue(&cb->txq) ;
  572.  
  573. #ifdef NR4DEBUG
  574.                 if (len_mbuf(bp) > NR4MAXINFO) {        /* should be checked higher up */
  575.                         cwprintf(NULL, "Upper layers queued too big a buffer\r\n") ;
  576.                         continue ;
  577.                 }
  578. #endif
  579.                 /* Set up and send buffer */
  580.                 
  581.                 tp = &cb->txbufs[cb->nextosend % cb->window] ;
  582.                 tp->retries = 0 ;
  583.                 tp->data = bp ;
  584.                 nr4sbuf(cb, cb->nextosend) ;
  585.  
  586.                 /* Update window and buffered count */
  587.  
  588.                 cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK ;
  589.                 if (++cb->nbuffered >= cb->window)
  590.                         break ;
  591.         }
  592.         return i ;              
  593. }
  594.  
  595. void nr4state(struct nr4cb *cb, int newstate)
  596. {
  597.         int i ;
  598.         int oldstate = cb->state ;
  599.         
  600.         cb->state = newstate ;
  601.  
  602.         switch (cb->state) {
  603.           case NR4STDPEND:
  604.                 stop_timer(&cb->tchoke);
  605.  
  606.                 /* When we request a disconnect, we lose the contents of */
  607.                 /* our transmit queue and buffers, but we retain our ability */
  608.                 /* to receive any packets in transit until a disconnect */
  609.                 /* acknowledge arrives */
  610.                 
  611.                 free_q(&cb->txq) ;
  612.                 
  613.                 for (i = 0 ; i < cb->window ; i++) {
  614.                         free_mbuf(cb->txbufs[i].data) ;
  615.                         cb->txbufs[i].data = NULLBUF ;
  616.                         stop_timer(&cb->txbufs[i].tretry) ;
  617.                 }
  618.                         
  619.                 break ;
  620.                 
  621.           case NR4STDISC:
  622.                 stop_timer(&cb->tchoke) ;
  623.                 stop_timer(&cb->tack) ;
  624.                 stop_timer(&cb->tcd) ;
  625.  
  626.                 /* We don't clear the rxq, since the state change upcall */
  627.                 /* may pull something off of it at the last minute. */
  628.                 
  629.                 free_q(&cb->txq) ;
  630.  
  631.                 /* The following loop will only be executed if the */
  632.                 /* window was set, since when the control block is */
  633.                 /* calloc'd the window field gets a 0 in it.  This */
  634.                 /* protects us from dereferencing an unallocated */
  635.                 /* window buffer pointer */
  636.                 
  637.                 for (i = 0 ; i < cb->window ; i++) {
  638.                         free_mbuf(cb->rxbufs[i].data) ;
  639.                         cb->rxbufs[i].data = NULLBUF ;
  640.                         free_mbuf(cb->txbufs[i].data) ;
  641.                         cb->txbufs[i].data = NULLBUF ;
  642.                         stop_timer(&cb->txbufs[i].tretry) ;
  643.                 }
  644.                         
  645.                 break ;
  646.         }
  647.  
  648.         if (oldstate != newstate && cb->s_upcall != NULLVFP)
  649.                 (*cb->s_upcall)(cb, oldstate, newstate) ;
  650.  
  651.         /* We take responsibility for deleting the circuit */
  652.         /* descriptor.  Don't do this anywhere else! */
  653.         
  654.         if (newstate == NR4STDISC)
  655.                 free_n4circ(cb) ;
  656.         
  657. }
  658.  
  659. /* Process NAKs.  seq indicates the next frame expected by the
  660.  * NAK'ing station.
  661.  */
  662.  
  663. void nr4gotnak(struct nr4cb *cb, unsigned seq)
  664. {
  665.         if (nr4between(cb->ackxpected, seq, cb->nextosend))
  666.                 nr4sbuf(cb, seq) ;
  667. }
  668.  
  669.  
  670. /* This is called when we first get a CHOKE indication from the
  671.  * remote.  It purges the send window and sets the choke timer.
  672.  */
  673.  
  674. void nr4choke(struct nr4cb *cb)
  675. {
  676.         unsigned seq ;
  677.         struct mbuf *q, *bp ;
  678.         struct nr4txbuf *t ;
  679.  
  680.         q = cb->txq ;
  681.  
  682.         /* We purge the send window, returning the buffers to the */
  683.         /* txq in the proper order. */
  684.  
  685.         for (seq = (cb->nextosend - 1) & NR4SEQMASK ;
  686.                  nr4between(cb->ackxpected, seq, cb->nextosend) ;
  687.                  seq = (seq - 1) & NR4SEQMASK) {
  688.  
  689.                 t = &cb->txbufs[seq % cb->window] ;
  690.                 stop_timer(&t->tretry) ;
  691.                 bp = t->data ;
  692.                 t->data = NULLBUF ;
  693.                 enqueue(&bp, q) ;       /* prepend this packet to the queue */
  694.                 q = bp ;
  695.          }
  696.  
  697.         cb->nextosend = cb->ackxpected ;        /* close the window */
  698.         cb->nbuffered = 0 ;                                     /* nothing in the window */
  699.         cb->txq = q ;                   /* Replace the txq with the one that has */
  700.                                                         /* the purged packets prepended */
  701.         cb->choked = 1 ;                /* Set the choked flag */
  702.  
  703.         start_timer(&cb->tchoke) ;
  704.         
  705. }
  706.  
  707.